package gates;

import java.math.*;
import java.awt.Graphics;

import master.*;

/**
 * Simple and universal Cnot gate using a fuctional implementation. Takes a control bit
 * and an action bit. Can then be applied to any QuantumRegister.
 * @author Rupert
 *
 */

public class Cnot extends QuantumGate {

        private int dim;
        private int N;
        private int cbit;
        private int abit;
        
        public Cnot(int cbit, int abit) {
                this.abit = abit+1;
                this.cbit = cbit+1;
                
        }

                        
        public void actOnReg(QuantumRegister reg) {
                this.N = reg.getQBitLength();
                this.dim = reg.getDimension();
        
                if(cbit == abit || (cbit>N) || (abit > N)) {
                        System.out.println("bit Error"); //display error message
                }
                if(cbit>abit) {
                        int d1 = (int)Math.pow(2,(cbit-1)); // unchanged (not changed states
                        int d2 = (int)Math.pow(2,(abit-1)); // size of block + forward backward jump
                        int d3 = (int)Math.pow(2,(cbit-abit-1)); // 
                        ComplexNumber[] mem = new ComplexNumber[1]; 
                        int no = (d1); // array starts counting at 0;
                        while(no<dim-1) {
                                for(int x = 0; x < d3;x++) {
                                        for(int n = no;n<(no+d2);++n) {
                                                mem[0] = reg.getCoefficient(n);
                                                reg.setCoefficient(reg.getCoefficient(n+d2), n);
                                                reg.setCoefficient(mem[0], n+d2);
                                        }
                                        no = no+2*d2;
                                }
                                no = no +d1;
                        }
                }
                // backward control part
                if(abit>cbit) {
                        int d1 = (int)Math.pow(2,(cbit-1)); // unchanged (not changed states + size of a block)
                        int d2 = (int)Math.pow(2,(abit-1)); //forward/backward jump 
                        int d3 = (int)Math.pow(2,abit); // size of circle
                        ComplexNumber[] mem = new ComplexNumber[1]; 
                        int no = (d1); // array starts counting at 0;
                        int count = d1;
                        while(no < (dim-1)) {
                                while(count < d3) {
                                        count = count +2*d1;
                                        for(int n = no; n<(no+d1);n++) {
                                                mem[0]= reg.getCoefficient(n);
                                                reg.setCoefficient(reg.getCoefficient(n+d2),n);
                                                reg.setCoefficient(mem[0],n+d2);
                                        }
                                        count = count + 2*d1;
                                        no = no+2*d1;
                                }
                                no = no+d2;
                                count = d1;
                        }
                }
        }
                
        
        
        public void draw(Graphics g, int x, int y, float scale) {
        g.drawOval(x-(int)(scale/4), y+(int)(scale/4)+(int)((cbit-1)*scale), (int)(scale/2), (int)(scale/2));
        g.fillOval(x-(int)(scale/4), y+(int)(scale/4)+(int)((abit-1)*scale), (int)(scale/2), (int)(scale/2));
        g.drawLine(
                        x, y+(int)(scale/2)+(int)((cbit-1)*scale),
                        x, y+(int)(scale/2)+(int)((abit-1)*scale));
        }       
        


     
        public int[] getActingBits() {
                return new int[]{cbit,abit};
        }



}